home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / X11 / tclMotif-1.4 / doc / tut < prev    next >
Encoding:
Text File  |  1995-06-29  |  17.3 KB  |  483 lines

  1.  
  2.  
  3. .de PS
  4. .in +10
  5. ..
  6. .de PE
  7. .in -10
  8. ..
  9.  
  10. .T tclMotif - a tutorial
  11.  
  12. .H 1 Basics
  13.  
  14. .H 2 Introduction
  15.  
  16. tclMotif is a binding of the tcl language to the Motif widget set.
  17. This allows access to most of the features of Motif through the
  18. simple language tcl, instead of the more complex C language that Motif is
  19. written in. 
  20.  
  21. There are major gains in this, primarily in code size and complexity: at
  22. tclMotif program typically is one tenth the length of the corresponding C
  23. program. It also dramatically simplifies some of the more complex areas of
  24. Motif programming, particularly in the handling of strings: tclMotif looks
  25. after the C code that otherwise the programmer would have to deal with. 
  26.  
  27. There is a downside, but it is comparatively minor. tcl is an interpreted
  28. language with a single data-type: string. There is a speed penalty in
  29. converting to and from strings. This would bar tcl from, say, a realistic
  30. language for matrix manipulations. However, sitting above a large and
  31. complex widget toolkit such as Motif, this speed penalty is not noticeable.
  32. tcl does not have the structuring and hiding capabilities of C, nor the
  33. object language mechanisms of C++. This may cause problems in very large
  34. projects, though tcl programs of over 100,000 lines in length (probably
  35. equivalent to 1,000,000 lines of C) do exist.
  36.  
  37. .H 2 "Starting moat
  38.  
  39. tclMotif is usually accessed through an interpreter called ``moat''. This
  40. is an interpreter that can either run interactively or on a tclMotif file.
  41. If the command is typed with no arguments then it displays the prompt
  42. .PS
  43. %
  44. .PE
  45. This acts just like the ordinary tcl interpreter ``tclsh'', and tcl
  46. commands can be typed into this interpreter just like into tclsh. The only
  47. difference is that it will also accept the additional Motif commands
  48. supplied by tclMotif.
  49.  
  50. When run with a single argument that is the name of a file as in
  51. .PS
  52. moat example1
  53. .PE
  54. it will read tclMotif commands from the file (here, ``example1'') and
  55. execute them.
  56.  
  57. There is a third way of running tclMotif, and this is the most common use.
  58. It relies on a number of things to make it work, though. First, the
  59. ``moat'' program must be installed in a standard place. Most tcl-based
  60. interpreters such as tclsh and moat assume that this is in the directory
  61. /usr/local/bin. If neccessary, you or your system supervisor should ensure
  62. that moat is either in this directory or that a link is made from this
  63. directory to it. Secondly, yous must be running a suitable command shell.
  64. All of the common shells such as sh, ksh, csh, bash, ksh, tcsh, zsh are
  65. fine. With these given, you can run a file as a tclMotif progam program by
  66. .AL 1
  67. .LI
  68. Making the first line of the file
  69. .PS
  70. #!/usr/local/bin/moat
  71. .PE
  72. .LI
  73. Making the file executable by
  74. .PS
  75. chmod u+x <file>
  76. .PE
  77. .LE
  78. From then on, using the filename as a command will invoke the moat
  79. interpreter to read and execute the rest of the file.
  80.  
  81. .H 2 "Hello World
  82.  
  83. Motif programs run under an event driven model. That is, objects are
  84. created that respond to events such as button presses, key strokes, and
  85. other things such as being covered and uncovered by other windows. To
  86. manage this, Motif relies on a toolkit called Xt that allows objects to be
  87. created and handles the events to the obects. Any Xt-based system must
  88. start up the Xt world, create some objects and then hand control to an Xt
  89. event handler that sits in a loop reading and processing events.
  90.  
  91. In tclMotif, the Xt world is started by a call to ``xtAppInitialize''. This
  92. creates a special object ``.'' which is used to build all other objects
  93. from. Two special calls are made to this object: ``realiseWidget'' that
  94. creates windows for all objects, and ``mainLoop'' that enters the event
  95. processing loop.
  96.  
  97. The actual objects are supplied by Motif. For ``Hello World'' a very
  98. simple object can be used because it just has to display a piece of text.
  99. This object is a Label. It is created by a call ``xmLabel'', and has its
  100. labelString value set to ``Hello world''
  101. .PS
  102. xtAppInitialize
  103. xmLabel .label -labelString "Hello world"
  104. . realizeWidget
  105. . mainLoop
  106. .PE
  107.  
  108. All widgets are ultimately descended from the toplevel widget ``.''. The
  109. hierarchy is shown explicitly in the widget names, so ``.label'' is an
  110. immediate child of ``.''. This is similar to the path name for files in
  111. Unix, with the ``.'' taking the place  of the Unix file separator ``/''.
  112. The third and fourth lines are method calls for the  ``.'' object to
  113. create windows and enter the event loop.
  114.  
  115. .H 2 "Creating widgets
  116.  
  117. Motif has a large number of widgets. In C, there is a function to create
  118. each one of them as XmCreate<widget>. tclMotif simplifies this a little to
  119. xm<widget>. So in the example above ``xmLabel'' creates a Label widget.
  120. Similarly, ``xmText'' creates a Text widget, ``xmList'' creates a List
  121. widget and so on. A program that creates a PushButton widget showing
  122. ``Hello world'' is
  123. .PS
  124. xtAppInitialize
  125. xmPushButton .label -labelString "Hello world"
  126. . realizeWidget
  127. . mainLoop
  128. .PE
  129. where only the widget creation command has changed.
  130.  
  131. Each widget has a parent, so that widgets form a tree. The toplevel widget
  132. is ``.'' and forms the root of this tree. The toplevel widget is created by
  133. the command ``xtAppInitialize''.  A widget is known by name, which is
  134. specified as the first argument to the widget creation command. This name
  135. contains the full path from ``.''. In the examples shown, this path is very
  136. short, as each widget is just the child of ``.'' It is worth noting at this
  137. point that the toplevel widget can only have one widget child at a time
  138. (except for dialog widgets which are discussed later).
  139.  
  140. In general, an application will consist of a non-trivial tree of widgets.
  141. Some widgets are \fI container \fP widgets, whose purpose is to contain and
  142. manage their children. The major containers are RowColumn, Form and
  143. MainWindow.
  144.  
  145. In most instances, a MainWindow widget will be the immediate child of ``.'',
  146. as this is set up to support a menu bar and a principal window containing
  147. the application, with optionally some scrollbars to control the visible
  148. area of the application.
  149.  
  150. A Form is used for arbitrary geometry arrangements, whereas a RowColumn is
  151. used for regular arrangements. In this example, a RowColumn inside a
  152. MainWindow holds a set of Labels:
  153. .PS
  154. xmMainWindow .main
  155. xmRowColumn .main.rc
  156. xmLabel .main.rc.label1
  157. xmLabel .main.rc.label2
  158. xmLabel .main.rc.label3
  159. .PE
  160.  
  161. A widget when created will not show on the screen. Windows have to be
  162. created, which is done by ``. realizeWidget''. In addition, a container
  163. will not show a widget unless it has been placed under the geometry
  164. management of the parent. This is done either at creation time with an
  165. optional second parameter ``managed'' or by a special method
  166. ``manageChild'':
  167. .PS
  168. xmLabel .main.rc.label1 managed 
  169. xmLabel .main.rc.label2
  170. .main.rc.label2 manageChild
  171. .PE
  172.  
  173. .H 2 "Resource control
  174.  
  175. A widget has many configurable properties. For example, in a Label widget
  176. the label itself can be set; in addition, the font used to render the label
  177. is configurable, as well as whether it should be centred or justified to
  178. the right or left. Width, height, foreground and background colour are
  179. configurable properties for most widgets. Each of these properties is
  180. called a \fI resource \fP, and the value is called a \fI resource value\fP.
  181.  
  182. The set of resources and possible values is documented for each widget.
  183. For example, the ArrowButton widget has a resource ``arrowDirection'' with four
  184. possible values: arrow_up, arrow_down, arrow_left and arrow_right. Resources
  185. can be set using the method ``setValues'' for each widget, or at creation
  186. time.
  187.  
  188. To set resources at creation time, a list of resource names/resource value
  189. pairs follows the widget name. For example,
  190. .PS
  191. xmArrowButton .arrow managed \
  192.     -arrowDirection arrow_up \
  193.     -width 100 \
  194.     -height 100
  195. .PE
  196.  
  197. To set resources at any time, the set of name/value pairs follows the
  198. method name, as in
  199. .PS
  200. .arrow setValues \
  201.     -arrowDirection arrow_down \
  202.     -width 50
  203. .PE
  204.  
  205. In a similar manner, resource values can be obtained from a widget by using
  206. the method getValues. This also takes a list of pairs, this time the
  207. resource name and a tcl variable to store the value in. For example, to
  208. find the width and height of a widget and store them in variables w and h
  209. respectively,
  210. .PS
  211. .arrow getValues \
  212.     -height h \
  213.     -width w
  214. .PE
  215.  
  216. .H 2 "Callback functions
  217.  
  218. When a button is pushed, when a list item is selected, when a key is
  219. pressed using a Text widget, etc, the widget reacts in some way. For
  220. example, the pressed button appears to sink into the surface, the list item
  221. is highlighted, and the character pressed is entered into the Text widget.
  222. This is also the time that suitable user code is executed. When the widget
  223. executes one of the internal actions that changes its state it can call tcl
  224. code that has been registered with the widget. Such code is attached to a
  225. ``callback'' and is called ``callback code''. Each widget has a documented
  226. set of callbacks. For example, for PushButton there is the
  227. activateCallback. activateCallback code is executed whenever the button is
  228. pressed and released. In a similar manner, when the List is in single-select mode,
  229. whenever an item is selected code attached to the singleSelectionCallback
  230. is executed.
  231.  
  232. Code is attached to the callback by using the appropriate callback method.
  233. There is a callback method for each of a widget's callbacks, and the code
  234. is given as the argument to this method. For example, to say ``Ouch''
  235. whnever the button is pressed and released, 
  236. .PS
  237. .btn activateCallback {puts stdout "Ouch"}
  238. .PE
  239.  
  240. Any tcl code may be placed in the callback. For example, a call to a
  241. function may be made, or a series of calls may be made. For example,
  242. .PS
  243. .btn activateCallback { 
  244.     puts stdout "That"
  245.     puts stdout "hurt!"
  246. }
  247. .PE
  248.  
  249. Callback code is executed in the global context, so that any unevaluated
  250. variables are evaluated at runtime in the global environment. That is,
  251. in
  252. .PS
  253. .btn activateCallback {puts stdout $msg}
  254. .PE
  255. the braces {} protect the variable msg against expansion when the code is
  256. attached to the callback. When the code is actually executed the variable
  257. msg will be evaluated as a global variable.
  258.  
  259. When a callback is invoked, there is often a great deal of useful
  260. information that is available to the callback code. The simplest and most
  261. commonly used of these is the widget name. This and other information can
  262. be found by means of a pattern which always starts with ``%''. For example,
  263. the pattern for the widget name is ``%w'':
  264. .PS
  265. .btn activateCallback \
  266.     {puts stdout "widget %w was pushed"}
  267. .PE
  268.  
  269. .H Rowcolumn
  270.  
  271. .H Form
  272.  
  273. .H 2 Menus
  274.  
  275. .H 2 "Dialog widgets
  276.  
  277. .H 2 List
  278.  
  279. .H 2 Text
  280.  
  281. .H 2 "Extended example
  282.  
  283. xmeditor is an editor based on the Text widget. It gains all of its edit
  284. functionality from the Text widget, so that this program is basically just
  285. a wrapper around this widget. Nevertheless, it shows a large number of the
  286. features of tclMotif. This example is a modification of the
  287. xmeditor example that appears as an example in the Motif distribution.
  288.  
  289. .H 3 "Xt world
  290. There is a section to setup the basic geometry and start the Xt world
  291. going:
  292. .PS
  293. xtAppInitialize \
  294.         -fallbackResources {
  295.                 {*XmText.columns: 80}
  296.                 {*XmText.rows: 24}
  297.         }
  298.  
  299. xmMainWindow .main managed
  300.  
  301. # menu stuff to create .main.menuBar goes in here
  302. # ....
  303.  
  304. xmScrolledText .main.text managed \
  305.         -editMode multi_line_edit
  306. .main.text modifyVerifyCallback {set fileSaved 0}
  307.  
  308.  
  309. .main setValues -menuBar .main.menuBar \
  310.                 -workWindow [.main.text parent]
  311.  
  312. . realizeWidget
  313. . mainLoop
  314. .PE
  315.  
  316. The fallback resources set the default sizes of the Text widget. These can be
  317. overridden by user or app-defaults files.
  318. The application resides inside a MainWindow, which contains a menu bar and a 
  319. ScrolledText widget. The relation of the children within the MainWindow by
  320. the line
  321. .PS
  322. .main setValues -menuBar .main.menuBar \
  323.                 -workWindow [.main.text parent]
  324. .PE
  325. which sets the menuBar and workWindow resources. Note that the 
  326. .I parent
  327. of the Text widget has to be used. This is the only way to get at the
  328. ScrolledWindow that is the real child of the MainWindow.
  329.  
  330. The Text widget by default is a single-line editor. This is clearly
  331. inappropriate here and is not even something that you would want to
  332. leave to user resource files. So the editMode resource is hard-coded
  333. to have the value ``multi_line_edit''.
  334. There is a callback set for the Text widget: whenever any text is entered
  335. into the widget, changing its contents, the global variable fileSaved is
  336. set to false, so that the application can determine that the file on disk
  337. is not the same as in the widget.
  338.  
  339. Finally, all windows are created by calling ``realizeWidget'' on the
  340. widget ``.'', and mainLoop is entered on the same widget.
  341.  
  342. .H 3 "Menu system
  343.  
  344. The menu system consists of three toplevel entries: File, Edit and Help.
  345. Under File is the pulldown with New, Open, Save, Save As..., Quit. Under
  346. Edit is the pulldown with entries Cut, Copy, Paste and Clear. Help has only
  347. one entry, About.
  348.  
  349. The subset of this that defines the menubar and the file pulldown is
  350. .PS
  351. xmMenuBar .main.menuBar managed
  352.  
  353. # file pulldown
  354. xmPulldownMenu .main.filePane
  355. xmCascadeButton .main.menuBar.File managed \
  356.         -subMenuId .main.filePane
  357.  
  358. xmPushButton .main.filePane.New managed
  359. .main.filePane.New activateCallback newFileCB
  360.  
  361. xmPushButton .main.filePane.Open managed
  362. .main.filePane.Open activateCallback openFileCB
  363.  
  364. xmPushButton .main.filePane.Save managed
  365. .main.filePane.Save activateCallback "saveFile"
  366.  
  367. xmPushButton .main.filePane.SaveAs managed
  368. .main.filePane.SaveAs activateCallback "saveFileAsCB"
  369.  
  370. xmPushButton .main.filePane.Quit managed
  371. .main.filePane.Quit activateCallback quitFileCB
  372. .PE
  373.  
  374. A small comment is in order: the buttons pick up their labelString value by
  375. default from their name, which is File, New, etc. This gives the default as
  376. English names. If other names are desired, they may be set using resources
  377. files. 
  378.  
  379. Each of these buttons calls a callback function. These functions will be
  380. discussed later.
  381.  
  382. .H 3 "File state
  383.  
  384. The contents of the editor may be the same as the external file. This
  385. will occur after a Save and before any changes have occurred, after
  386. the file has been loaded, or when a new file has been created. In this
  387. case, many actions such as exiting the editor or loading a new file
  388. can be done without any problems. On the other hand, the two may have
  389. different contents. In this case many actions may need to call up a
  390. dialog of some kind. In xmeditor this state is represented by the tcl
  391. variable ``fileSaved''. In various places the value of this is set to
  392. 1 (true). It is set to 0 (false) every time a change is made to the
  393. widget contents through an edit action. This is handled very easily in
  394. the ``modifyVerifyCallback'' which is called on every text entry by the
  395. user:
  396. .PS
  397. .main.text modifyVerifyCallback {set fileSaved 0}
  398. .PE
  399.  
  400. .H 3 "Saving and loading
  401.  
  402. Two simple procedures are just concerned with saving the text from the
  403. Text widget and loading it from a file. These are ``saveFile'' and 
  404. ``loadFile''. The Motif part of saveFile of interest is extracting
  405. the contents from the Text widget:
  406. .PS
  407. set str [.main.text getString]
  408. .PE
  409. Similarly, from loadFile, lines are read fromthe file and placed in the
  410. Text widget by
  411. .PS
  412. .main.text setString ""
  413. while {[gets $fileID str] >= 0} {
  414.     .main.text insert [.main.text getLastPosition]] "$str\n"
  415. }
  416. .PE
  417. This reads lines successively and inserts them at the end of the text in
  418. the widget.
  419.  
  420. .H 3 "Save dialog
  421.  
  422. One of the more complex functions is ``saveFileDialog''. This function
  423. is called when an action such as repalcing the contents of the Text
  424. widget with new text has been requested, but the current contents have
  425. not been saved. The proper action in this case is to request confirmation
  426. from the user to save or discard the contents. Usually such a confirmation
  427. is run as a 
  428. .I modal
  429. dialog
  430. i.e. it must be answered before any other interaction with the application
  431. is allowed.
  432.  
  433. Creating the dialog is straightforward, as it is just an errorDialog with
  434. messageString set to a ``Save file?'' message. making it modal is done
  435. in several stages. First the dialog is made modal by setting the
  436. ``dialogStyle'' resource to dialog_full_application_modal. 
  437. This in itself is enough to ensure that no
  438. interaction with the rest of the application can take place.
  439. .PS
  440. xmErrorDialog .fileSaveDialog managed \
  441.     -messageString "Save $currentFile?" \
  442.     -dialogStyle dialog_full_application_modal
  443. .PE
  444.  
  445. While this sets the interaction style with the application, it does not set
  446. the control flow in the program. The use of such modal dialogs is often
  447. in linear code:
  448. .PS
  449. if modal_dialog returns true
  450.    do something
  451. else
  452.    do something else
  453. .PE
  454. To ensure this kind of logic, the dialog function itself cannot return
  455. until the dialog is over. The simplest way of ensuring this is to enter
  456. an event loop within the dialog function, which only terminates when the
  457. dialog is over. This in turn will only happen when the user presses either
  458. the Cancel or OK buttons. So an event loop must be set up which only
  459. terminates when the Cancel or OK callbacks are invoked:
  460. .PS
  461. global stillModal
  462. global answer
  463.  
  464. .fileSaveDialog okCallback {set stillModal 0; set answer 1}
  465. .fileSaveDialog cancelCallback {set stillModal 0; set answer 0}
  466.  
  467. set stillModal 1
  468. while {$stillModal} {
  469.     . processEvent
  470. }
  471. .PE
  472.  
  473. .H 3 "File selection
  474.  
  475. At various points, a file must be chosen. This should be done by a 
  476. FileSelection dialog. This selects a file and loads it:
  477. .PS
  478. xmFileSelectionDialog .fsd managed
  479.     .fsd.Help unmanageChild
  480.     .fsd okCallback {loadFile %w %value}
  481.     .fsd cancelCallback {[.fsd parent] destroyWidget}
  482. .PE
  483.